package com.example.camera_study;

import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.Semaphore;

public class CameraUtils{
    boolean isstop;
    Context context;
//    SurfaceTexture surfaceTexture;

    String TAG = "CameraUtils";
    String cameraID;
    CameraManager cameraManager;
     CameraDevice cameraDevice;
    CameraCharacteristics cameraCharacteristics;
//    Surface surface;
    CaptureRequest.Builder builder;
     HandlerThread mBackgroundforcameraThread;
     Handler mBackgroundforcameraHandler;
    //预览宽高
    int width=1280;
    int height=720;
    //摄像头完成打开动作后回调
    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            cameraDevice = camera;
//            surfaceTexture = textureView.getSurfaceTexture();
//            surfaceTexture.setDefaultBufferSize(1280, 720);
//            surface = new Surface(surfaceTexture);
            Log.i(TAG, "回调onOpened");
            Log.d(TAG, "相机初始化成功id： "+cameraID);
            if(cameraEventListener != null) {
                cameraEventListener.onInitSuccess(cameraDevice);
            }
//            try {
//                builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
//                builder.addTarget(surface);
//            } catch (CameraAccessException e) {
//                throw new RuntimeException(e);
//            }

        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            Log.d(TAG, "onDisconnected: ");
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            Log.d(TAG, "onError: ");

//            openCamera();
            if (cameraEventListener != null){
                cameraEventListener.onInitFail(error);
            }


        }

    };
    CaptureRequest captureRequest;
    CameraCaptureSession preview_session;
    CameraCaptureSession recoder_session;
    CameraCaptureSession.StateCallback msessionstatecallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {//摄像头设备完成自身配置的时候调用
            preview_session=session;
//             captureRequest = builder.build();
//            try {
//                session.setRepeatingRequest(captureRequest,null,mBackgroundforcameraHandler);
//            } catch (CameraAccessException e) {
//                throw new RuntimeException(e);
//            }
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {

        }
    };
//开启预览
//    public void startPreview(){
//        try {
//            cameraDevice.createCaptureSession(Arrays.asList(surface), msessionstatecallback, null);
//        } catch (CameraAccessException e) {
//            throw new RuntimeException(e);
//        }
//
////                     captureRequest = builder.build();
////            try {
////                Toast.makeText(context, "开启预览", Toast.LENGTH_SHORT).show();
////
////                preview_session.setRepeatingRequest(captureRequest,null,mBackgroundforcameraHandler);
////            } catch (CameraAccessException e) {
////                throw new RuntimeException(e);
////            }
//    }
    //停止预览
    public void stopPreview(){
        try {
            Toast.makeText(context, "停止预览", Toast.LENGTH_SHORT).show();

            preview_session.stopRepeating();
        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }
    }
    FileObserver observer;
    public CameraUtils(CameraManager cameraManager,String cameraID,Context context,HandlerThread mBackgroundforcameraThread,Handler mBackgroundforcameraHandler) {
        this.context=context;
        this.cameraID = cameraID;
        this.cameraManager = cameraManager;
        this.mBackgroundforcameraThread = mBackgroundforcameraThread;
        this.mBackgroundforcameraHandler = mBackgroundforcameraHandler;
        record_path="/sdcard/DCIM/"+System.currentTimeMillis()+".mp4";
        Log.d(TAG, "record_path: "+record_path);
        observer = new FileObserver(record_path) {
            @Override
            public void onEvent(int event, String path) {
//                Log.d(TAG, "onEvent: ");
// 处理事件
                if (event == FileObserver.CREATE) {
//                    Log.d(TAG, "处理文件或目录创建事件 "+record_path);
// 处理文件或目录创建事件
                } else if (event == FileObserver.DELETE) {
// 处理文件或目录删除事件
                } else if (event == FileObserver.MODIFY) {
//                    Log.d(TAG, "处理文件修改事件 "+record_path);
// 处理文件修改事件
                }else if (event == FileObserver.CLOSE_WRITE) {
                    Log.d(TAG, "以可写属性打开的文件被关闭  路径： "+record_path);

                    observer.stopWatching();
                    // 以可写属性打开的文件被关闭
                }
            }
        };

    }

        private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {

        }

        @Override
        public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

        }
    };

    //    stateCallback=new CameraDevice.StateCallback();
    public void openCamera() {
        if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        try {

            cameraManager.openCamera(cameraID, mStateCallback, mBackgroundforcameraHandler);
        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }

    }


    String record_path;
    //开启录像
     CaptureRequest.Builder mPreviewRequestBuilder;
     MediaRecorder mediaRecorder;
     Surface recorderSurface;

     public void startRecord(){
         Log.d(TAG, "startRecord: ");
         openCamera();

        if (mediaRecorder==null){
            mediaRecorder=new MediaRecorder();
        }
         mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
         mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
         //设置录制存储路径

         String mNextVideoAbsolutePath =record_path;
         mediaRecorder.setOutputFile(mNextVideoAbsolutePath);
         mediaRecorder.setVideoEncodingBitRate(1100000);
         mediaRecorder.setVideoSize(1280, 720);

         mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

         mediaRecorder.setVideoFrameRate(30);
         mediaRecorder.setCaptureRate(30);
//        mMediaRecorder.setAudioEncodingBitRate(96000);

         //编码格式
//        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
         mediaRecorder.setOrientationHint(180);

         mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
             @Override
             public void onError(MediaRecorder mr, int what, int extra) {
                 if(cameraEventListener!= null){
                     cameraEventListener.onRecorderError(mr, what, extra);
                 }
                

             }
         });
        try {
            mediaRecorder.prepare();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        recorderSurface = mediaRecorder.getSurface();
       
        try {
            mPreviewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }
        mPreviewRequestBuilder.addTarget(recorderSurface);
        try {
            cameraDevice.createCaptureSession(Arrays.asList(recorderSurface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {//摄像头设备完成自身配置的时候调用
                    recoder_session=session;
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
                    captureRequest = mPreviewRequestBuilder.build();
                    try {
                        recoder_session.setRepeatingRequest(captureRequest,null,null);
                    } catch (CameraAccessException e) {
                        throw new RuntimeException(e);
                    }
                    mediaRecorder.start();
                    observer.startWatching();
                    Log.d(TAG, "开启录像id: "+cameraID);
                    Toast.makeText(context, "开启录像", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                }
            }, null);
        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }

    }
    public void startR(){


    }

    //停止录像

    public void stopRecord(){
if (!isstop){
        mediaRecorder.stop();
    Log.d(TAG, "stopRecord ");
        isstop=true;}
        mediaRecorder.setOnErrorListener(null);
if (cameraDevice!=null){
        cameraDevice.close();
        cameraDevice=null;}
        Toast.makeText(context, "录像成功，保存在sdcard/DCIM/目录下", Toast.LENGTH_SHORT).show();

    }

    //拍照
    CameraCaptureSession photo_session;
    CaptureRequest.Builder mCaptureBuilder;
    public void takePhoto(){
        //前三个参数分别是需要的尺寸和格式，最后一个参数代表每次最多获取几帧数据
        mImageReader = ImageReader.newInstance(width, height,
                ImageFormat.JPEG, 1);
        try {
            mCaptureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        } catch (CameraAccessException ex) {
            throw new RuntimeException(ex);
        }

        mCaptureBuilder.addTarget(mImageReader.getSurface());
        try {
            cameraDevice.createCaptureSession(Arrays.asList(mImageReader.getSurface()),  new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {//摄像头设备完成自身配置的时候调用
                    Log.d(TAG, "onConfigured: ");
                    photo_session=session;
                    mCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION,null);

                    CaptureRequest captureRequest = mCaptureBuilder.build();
                    try {
                        photo_session.capture(captureRequest,captureCallback,mBackgroundforcameraHandler);
                    } catch (CameraAccessException ex) {
                        Toast.makeText(context, "拍照失败", Toast.LENGTH_SHORT).show();
                        throw new RuntimeException(ex);
                    }
//             captureRequest = builder.build();
//            try {
//                session.setRepeatingRequest(captureRequest,null,mBackgroundforcameraHandler);
//            } catch (CameraAccessException e) {
//                throw new RuntimeException(e);
//            }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Log.d(TAG, "onConfigureFailed: ");
                }
            }, null);
        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }





        //监听ImageReader的事件，当有图像流数据可用时会回调onImageAvailable方法，它的参数就是预览帧数据，可以对这帧数据进行处理
        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image image = reader.acquireLatestImage();
                // 开启线程异步保存图片
                new Thread(new ImageSaver(image)).start();


            }
        }, null);

    }
    //拍照回调
    CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {

        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                       @NonNull CaptureRequest request,
                                       @NonNull TotalCaptureResult result) {
            Toast.makeText(context, "拍照成功", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "拍照成功回调 ");
            if (cameraEventListener != null) {
                cameraEventListener.onTakePicture();
            }
            photo_session.close();
            photo_session=null;
            cameraDevice.close();
            cameraDevice=null;

        }

        @Override
        public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
            photo_session=session;
            Log.d(TAG, "onCaptureFailed: ");
            super.onCaptureFailed(session, request, failure);
        }
    };
    ImageReader mImageReader;

    

    //设置图片保存路径
    public  class ImageSaver implements Runnable {


        private Image mImage;
        private File mImageFile;

        public ImageSaver(Image image) {
            mImage = image;
        }

        @Override
        public void run() {
            ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            mImageFile = new File(Environment.getExternalStorageDirectory() + "/DCIM/" + System.currentTimeMillis() + ".jpg");


            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(mImageFile);
                fos.write(data, 0, data.length);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                mImageFile = null;
                if (fos != null) {
                    try {
                        fos.close();
                        mImage.close();
                        fos = null;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    private CameraEventListener cameraEventListener;

    public void setCameraEventListener(CameraEventListener cameraEventListener) {
        this.cameraEventListener = cameraEventListener;
    }

    /**
     * 要求：
     * 1.需要知道摄像头是否初始化成功。
     * 2.需要提供拍照并且保存到SD卡的摄像头的接口。
     * 3.需要提供录制并且保存到SD卡的摄像头接口。
     * 只需要提供以上几个接口即可。
     */
    interface CameraEventListener{
        /**
         * 相机初始化成功回调
         * @param cameraDevice
         */
        void onInitSuccess(CameraDevice cameraDevice);

        /**
         * 相机初始化失败回调
         * @param  error
         */
        void onInitFail(int error);

        /**
         * 拍照成功回调
         * @param
         */
        void onTakePicture();

        /**
         * 录制过程发生异常, 由原生 {@link MediaRecorder.OnErrorListener} 中返回
         * 具体参数含义请查看 android sdk
         */
        void onRecorderError(MediaRecorder mr, int what, int extra);
    }
}
